longChain 学习
March 31, 2023
最近了解 Open AI 的过程中发现这个框架,把中文文档整理如下
LangChain 是一个使用语言模型驱动应用程序开发的框架。最强大、最具差异化的应用程序不仅仅通过 API 调用语言模型,还将具备以下特点:
- 数据感知:将语言模型与其他数据源连接起来。
- 自主性:允许语言模型与其环境进行交互。
该框架旨在遵循上述原则。 本文档的重点是针对 Python 的部分。如需了解关于 LangChain 的纯概念指南,请参见此处。如需 JavaScript 文档,请参见此处。 LangChain 框架提供了两个主要价值:
- 组件:LangChain 提供了模块化的抽象组件,用于与语言模型配合使用。LangChain 还提供了这些抽象的所有实现集合。这些组件旨在易于使用,无论您是否使用 LangChain 框架的其余部分都是如此
- 特定用例的链:链可以被视为以特定方式组装这些组件,以最好地完成特定用例。这些旨在成为通过它们,人们可以轻松地开始使用特定用例的更高级别的接口。这些链也被设计为可自定义的。
因此,我们将以下文档分为这两个主要价值。在本文档中,我们以高层次和与语言无关的方式概述组件和用例。有关使用这些组件和解决这些用例的特定语言方法,请参见页面顶部链接的特定语言部分。
Components
Schema:
- Text:在使用语言模型时,与其互动的主要接口是文本。简单来说,许多模型是“输入文本,输出文本”。因此,LangChain 中的许多接口都是以文本为中心。
- ChatMessages:最主要的用户接口是通过聊天界面进行互动。因此,一些模型提供者甚至开始以期望聊天消息的方式提供对底层 API 的访问。这些消息具有内容字段(通常是文本),并与用户相关联。目前支持的用户包括系统、人类和人工智能。
- SystemChatMessage:一条聊天消息,代表应该传达给人工智能系统的指令信息。
- HumanChatMessage:一条聊天消息,代表与人工智能系统互动时来自人类用户的信息。
- AIChatMessage:一条聊天消息,代表来自人工智能系统的信息。
- Examples:示例是代表函数的输入和期望输出的输入/输出对。它们可以用于模型的训练和评估。这些示例可以是模型或链的输入/输出。两种类型的示例具有不同的用途。用于模型的示例可用于精细调节模型。用于链的示例可用于评估端到端链路,甚至可以训练模型以代替整个链路。
- Document:一段非结构化数据,包括
page_content
(数据内容)和metadata
(描述数据属性的辅助信息)
Models
本文档部分涉及LangChain中使用的不同类型模型。在本页面,我们将概述各种模型类型,但对于每种模型类型我们都有单独的页面。
LLMs
大型语言模型(LLMs)是我们介绍的第一种类型的模型。这些模型以文本字符串作为输入,并返回文本字符串作为输出。
聊天模型
聊天模型是我们介绍的第二种类型的模型。这些模型通常由语言模型支持,但它们的API更加结构化。具体而言,这些模型以聊天消息列表作为输入,并返回聊天消息。
文本 Embedding # Model
以文本为输入,并返回浮点数列表(向量)
Prompts
新的模型编程方式是通过提示(Prompts)的方式。“Prompt”是指模型输入,这个输入很少被硬编码,通常由多个组件组成。PromptTemplate负责构建此输入。LangChain提供了多个类和函数,使得构建和使用prompt变得容易。 本文档分为四个部分:
- Prompt Value:代表模型输入的类。
- Prompt Templates:负责构建PromptValue的类。
- Example Selectors:通常在提示中包含示例是很有用的。这些示例可以硬编码,但如果它们是动态选择的,则通常更加强大。
- Output Parsers:语言模型(和聊天模型)输出文本。但是很多时候,您可能希望获得比纯文本更结构化的信息。这就是输出解析器发挥作用的地方。输出解析器负责
- (1)指示模型如何格式化输出
- (2)将输出解析为所需的格式(包括必要时进行重试)
Prompt Value
“提示”是指传递给底层模型的内容。LangChain中主要的抽象都是针对文本数据的提示。对于其他类型的数据(如图像、音频),我们正在努力添加抽象,但目前还没有实现。 不同的模型可能需要不同的数据格式。如果可能的话,我们希望允许在不同的模型类型中使用相同的提示。因此,我们有一个PromptValue的概念。这是一个类,它公开了一些方法,用于将提示值转换为每个模型类型所期望的精确输入类型(目前为文本或聊天消息)。
Prompt Templates
Prompt Value是最终传递给模型的内容。大多数情况下,这个值不是硬编码的,而是根据用户输入、其他非静态信息(通常来自多个来源)和固定的模板字符串动态创建的。 我们称负责创建Prompt Value的对象为Prompt Template。这个对象公开了一个方法,用于接收输入变量并返回PromptValue。
Example Selectors
在提示中包含prompt examples通常是很有用的。这些示例可以是硬编码的,但如果它们是动态选择的,通常会更有用。Example Selectors是接收用户输入并返回要使用的示例列表的对象
Output Parser
Output parser 是帮助构建 语言模型响应结构 的类。Output parser必须实现两个主要方法:
get_format_instructions() -> str
:返回一个包含有关如何格式化语言模型输出的字符串的方法。parse(str) -> Any
:接受一个字符串(假定为语言模型的响应),并将其解析成某些结构的方法。
还有一个可选的方法:
parse_with_prompt(str) -> Any
:接受一个字符串(假定为语言模型的响应)和提示语(假定生成此响应的提示语),并将其解析成某些结构的方法。提示语通常在输出解析器想要重新尝试或以某种方式修复输出时提供,需要从提示语中获取信息来进行操作
Indexes
Indexes 是指对文档进行结构化处理,以便 LLMs 能够最好地与它们交互的方式。该模块包含用于处理文档、不同类型的索引的实用函数,以及在链中使用这些索引的示例。 indexes在链中最常见的用法是在“retrieval”步骤中。这一步骤指的是将用户的查询与最相关的文档匹配。我们之所以提出这个区别是因为
- (1) indexe可以用于除retrieval以外的其他目的
- (2) retrieval可以使用除index以外的其他逻辑来查找相关文档。因此我们有一个“Retriever”接口的概念,这是大多数链所使用的接口。
当我们谈论索引和检索时,大多数情况下我们是在谈论索引和检索非结构化数据(例如文本文档)的情况。对于与结构化数据(SQL 表等)或 API 交互,请参见相应的用例部分,以获取相关功能的链接。LangChain 支持的主要索引和检索类型目前集中在向量数据库上,因此我们在这些主题上深入探讨了很多功能。
Document Loaders
文档加载器负责加载文档对象列表。
Text Splitters
通常,您希望将大型文本文档分割成较小的块,以便更好地使用语言模型。TextSplitter 负责将文档分割成更小的文档。
Retriever
一种存储数据的方法,以便可以通过语言模型进行查询。此对象必须公开的惟一接口是get_relevant_texts
方法,该方法接受字符串并返回 Document 列表。
Vectorstore
最常见的索引类型是创建每个文档的数值嵌入numerical embeddings(使用嵌入模型Embedding Model)。向量存储器存储文档及其相关的嵌入,并提供通过嵌入查找相关文档的快速方法。
Memory
Memory是在对话过程中存储和检索数据的概念。主要有两种方法:
- 基于输入,获取任何相关的数据
- 基于输入和输出,相应地更新状态
记忆主要分为短期和长期两种类型。 短期记忆通常指如何在单个对话的上下文中传递数据(通常是前面的聊天消息或其摘要)。 长期记忆涉及如何在对话之间获取和更新信息。
Chat Message History
当前与语言模型的主要接口是通过聊天接口实现的。ChatMessageHistory 类负责记住所有以前的聊天交互。然后可以将其直接传递回模型中,以某种方式进行总结,或进行某些组合。 ChatMessageHistory 公开了两种方法和一个属性。它公开的两个方法是 add_user_message 和 add_ai_message,用于相应地存储来自用户的消息和来自 AI 的响应。它公开的属性是 messages 属性,用于访问所有以前的消息。
Chains
Chains是一个非常通用的概念,它返回一个由模块化组件(或其他链)按特定方式组合而成,以完成常见用例。 最常用的链类型是LLMChain,它将PromptTemplate、Model和Guardrails组合在一起,以获取用户输入,相应地进行格式化,将其传递给模型并获得响应,然后验证并修复(如果需要)模型输出。
Chain
链只是围绕多个单独Component的端到端包装器
LLMChain
一个 LLMChain 是最常用的链式结构。它由 PromptTemplate、模型(LLM或ChatModel)和可选的输出解析器组成。这个链式结构接受多个输入变量,使用 PromptTemplate 将它们格式化成一个提示,然后将它传递给模型。最后,如果提供了 OutputParser,则使用它将LLM的输出解析成最终格式。
Index-related chains
这类链用于与索引交互。其目的是将您自己的数据(存储在索引中)与LLMs结合使用。其中最好的例子是在自己的文档上进行问答。 其中很重要的一部分是了解如何将多个文档传递给语言模型。有几种不同的方法或链,可以实现这一点。LangChain支持其中四种比较常见的方法,我们正在积极寻求更多的方法,如果您有任何想法,请联系我们!请注意,并没有一种最好的方法——选择使用哪种方法通常非常具体于上下文。
Stuffing
Stuffing是最简单的方法,你只需要将所有相关的数据作为上下文填充到prompt中,然后传递给语言模型。在LangChain中,这是通过StuffDocumentsChain来实现的。 优点:只需要对LLM进行一次调用。在生成文本时,LLM可以同时访问所有数据。 缺点:大多数LLM都有上下文长度限制,对于大型文档(或多个文档),这种方法将无法正常工作,因为它会导致一个大于上下文长度的prompt。 这种方法的主要缺点是,它只适用于较小的数据。一旦你处理大量的数据,这种方法就不再可行。接下来的两种方法旨在帮助解决这个问题。
Map Reduce
这种方法涉及对每个数据块运行初始提示(对于摘要任务,这可以是该块的摘要;对于问答任务,它可以是仅基于该块的答案)。然后运行一个不同的提示来组合所有初始输出。这在LangChain中实现为MapReduceDocumentsChain。 优点:可以扩展到比StuffDocumentsChain更大的文档(和更多文档)。对单个文档进行的LLM调用是独立的,因此可以并行化。 缺点:需要比StuffDocumentsChain更多的LLM调用。在最终的组合调用中会丢失一些信息。
Refine
这种方法是在第一个数据块上运行初始提示,生成一些输出。对于剩余的文档,将该输出与下一个文档一起传递,要求LLM基于新文档对输出进行细化。 优点:可以引入更相关的上下文,并且可能比MapReduceDocumentsChain损失更少。 缺点:需要比StuffDocumentsChain更多的LLM调用。这些调用也不是独立的,意味着它们不能像MapReduceDocumentsChain一样并行执行。还可能存在一些依赖于文档顺序的潜在依赖关系。
Map-Rerank
这种方法涉及在每个数据块上运行一个初始提示,不仅试图完成任务,而且还会给出它回答的可信度分数。然后根据这个分数对响应进行排名,并返回最高分数的响应。 优点:与MapReduceDocumentsChain类似的优点。与MapReduceDocumentsChain相比,需要更少的调用。 缺点:无法在文档之间合并信息。这意味着它在您预计单个文档中有一个简单答案时最有用。
Prompt Selector
LangChain 中链的一个目标是尽快让用户开始使用特定的用例,其中一个重要的部分是有一个好的prompts。 问题在于,一个适用于一个模型的prompt可能对于另一个模型不太适用。 我们希望让链在所有类型的模型上都能够很好地工作。因此,我们没有在链中硬编码默认提示信息,而是引入了 PromptSelector 的概念。这个 PromptSelector 负责根据传入的模型选择一个默认提示信息。 PromptSelectors 最常见的用例是为 LLMs 和 Chat Models 设置不同的默认提示信息。但是,如果需要,也可以用它来为不同的模型提供商设置不同的默认提示信息。
Agents
有些应用程序不仅需要预先确定的对LLMs/其他工具的调用链,还可能需要依赖于用户输入的未知链。在这些类型的链中,有一个“Agent”,该Agent可以访问一套工具。根据用户输入,Agent可以决定是否调用其中的任何一个工具。 我们将Document分为以下几个部分:
- Tools:语言模型与其他资源的交互方式:一个特定的抽象概念,用于使语言模型与其交互变得容易。具体来说,一个工具的接口具有一个文本输入和一个文本输出。
- Agents:驱动决策的语言模型:代理是模型的封装,它接收用户输入并返回相应的“动作”以及相应的“动作输入”。
- Toolkits:一组工具,当它们一起使用时可以完成特定的任务。
- Agent Executor:运行代理与工具的逻辑:Agent Executor 是一个 Agent 和一组Tools。Agent Executor 负责调用 Agent,得到对应的“行动”和“行动输入”,使用行动指示的工具和相应的输入调用该工具,得到工具的输出,然后将所有这些信息传递回 Agent,以获取它应该采取的下一个行动。
Use Cases
本节重点介绍 LangChain 可以帮助解决的不同端到端用例。对于每个用例,我们不仅激发了用例,而且还讨论了哪些组件对于解决该用例最有帮助。
Personal Assistants
个人助理是LangChain的两个核心价值主张(动作执行和个性化数据)的完美应用。为了构建个人助理,您应该了解以下概念: PromptTemplate-这将指导您的个人助理的行为。它们是俏皮还是有帮助的?这些可以用来给您的个人助理一些个性。 Memory-您的个人助理应该记住某些事情。他们肯定应该能够进行交谈(短期记忆),并且他们可能还需要一些长期记忆的概念。 Tools-通过给它提供工具,您的个人助理将会与众不同。它应该知道如何做什么? Agent-您的个人助理将不得不理解它应该采取哪些行动。构建最佳代理人将是重要的。 Agent Executor-在您拥有工具和代理人之后,为了将其付诸实践,您需要设置一个代理人使用这些工具的环境。这就是代理人执行者发挥作用的地方。
Question Answering Over Documents
LLMs虽然功能强大,但它们并不知道它们没有接受过培训的信息。如果您想使用LLM回答与其未接受培训的文档有关的问题,则必须向其提供有关这些文档的信息。最常见的方法是通过“检索增强生成”。
检索增强生成的思想是,当提出问题时,首先进行检索步骤以获取任何相关文档。然后将这些文档与原始问题一起传递给语言模型,并让它生成响应。但是,为了做到这一点,您首先必须以可查询的方式将文档格式化。本页面概述了这两个步骤的高级想法:(1)将文档导入可查询格式,然后(2)检索增强生成链。
导入
为了使用语言模型与您的数据进行交互,您首先必须将其转换为适当的格式。该格式将是索引。将数据放入索引中可使任何下游步骤轻松地与之交互。 有几种类型的索引,但迄今为止最常见的是向量存储。将文档导入向量存储可以通过以下步骤完成:
- 加载文档(使用Document Loader)
- 分割文档(使用Text Splitter)
- 为文档创建嵌入(使用Text Embedding Model)
- 将文档和嵌入存储在向量存储中
生成 现在我们有了索引,如何使用它来生成响应呢?这可以分解为以下步骤:
- 接收用户问题
- 在索引中查找与问题相关的文档
- 使用PromptTemplate从问题和任何相关文档构造PromptValue。
- 将PromptValue传递给模型
- 获取结果并返回给用户。
Chatbots
ChatGPT通过提供一个新的界面——聊天界面,将一个强大的语言模型引入了世界。构建聊天机器人需要几个组件。
- 模型 - 你可以从普通的语言模型或者Chat Model构建一个聊天机器人。重要的是要记住,即使你使用的是Chat Model,API本身也是无状态的,这意味着它不会记住以前的交互 - 你必须传递它们
- PromptTemplate - 这将指导您的聊天机器人如何表现。他们是率真的还是乐于助人的?这些可以用来赋予您的聊天机器人一些个性
- Memory - 如上所述,模型本身是无状态的。Memory带来了某种状态的概念,使它可以记住以前的交互。
聊天机器人通常与其他数据源结合使用时会更加强大和具有差异化。与“文档问答”背后的技术相同,也可以用于此处,以便让聊天机器人可以访问这些数据。
Querying Tabular Data
大量的数据和信息以表格形式存储,无论是CSV、Excel表格还是SQL表。本页面介绍了LangChain可用于处理此类数据的所有资源。
文档加载
如果您有以表格形式存储的文本数据,可能希望将数据加载到文档中,然后像处理其他文本/非结构化数据一样进行索引。为此,应使用CSVLoader等文档加载程序,然后创建一个索引来查询数据。
查询
如果您有更多的数字表格数据,或者有大量数据并且不想对其进行索引,您也可以直接使用语言模型与其交互。
Chains
如果您刚开始使用,且拥有相对较小/简单的表格数据,则应从链开始。链是一系列预定步骤,因此它们很适合入门,因为它们给予您更多控制权,让您更好地理解正在发生的情况。
Agents
代理更为复杂,涉及多次查询LMM以了解要执行的操作。代理的缺点是您的控制权更少。优点是它们更强大,使您能够在更大的数据库和更复杂的模式上使用它们。
Interacting with APIs
APIs的强大之处在于它们既可以通过它们执行操作,还可以通过它们查询数据。本页面介绍LangChain中可用于处理API的所有资源。
Chains
如果您刚开始使用,且您有一个相对较小/简单的API,则应该从链开始。链是一系列预定步骤,因此它们很适合入门,因为它们给予您更多的控制,并让您更好地了解发生的情况。
Agents
代理更为复杂,涉及多次查询LMM以了解要执行的操作。优点是它们更加强大,可以在更大或更复杂的API上使用。
Extraction
语言模型实际上非常擅长从非结构化文本中提取结构化信息。这很有用,因为许多信息以文本形式存储,但为了使其在下游使用起来更加方便,通常需要将其转换为结构化格式。 在这里最有用的概念是“OutputParsers”(输出解析器)。OutputParser 负责指定语言模型应该响应的模式,然后将其原始文本输出解析为该结构化格式。。 使用它们进行提取的方法是定义要在 OutputParser 中提取的信息的模式。然后,您将创建一个接收原始文本 blob 的 PromptTemplate,其中包含以指定格式提取信息的说明。
Evaluation
LangChain评估部分的文档涵盖了我们在LangChain中如何处理和思考评估的方法。这包括对内部chains/agents进行评估的方法,以及我们建议在LangChain上构建的人如何进行评估的方法。
问题 评估LangChain chains/agents可能会很困难。这主要有两个原因:
1:缺乏数据
在开始一个项目之前,通常你没有太多的数据可以评估你的chains/agents。这通常是因为大型语言模型(大多数chains/agents的核心)是非常好的few-shot和zero-shot学习者,这意味着你几乎总是能够开始执行特定的任务(文本到SQL、问答等),而不需要大量的样本数据。这与传统的机器学习形成了鲜明的对比,在传统机器学习中,你必须先收集一堆数据点,然后才能开始使用模型。
2:缺乏指标
大多数chains/agents执行的任务没有很好的指标来评估性能。例如,最常见的用例之一是生成某种形式的文本。评估生成的文本要比评估分类预测或数值预测复杂得多。 解决方案 LangChain试图解决这两个问题。目前我们的解决方案是初步的,我们认为还没有完美的解决方案。因此,我们非常欢迎反馈、贡献、集成和关于此的想法。
对于每个问题,我们目前的解决方案如下:
1:缺乏数据
我们已经开始使用Hugging Face社区空间中的LangChainDatasets收集开源数据集,用于评估常见的chains和agents。我们已经为此贡献了五个数据集,但我们高度希望这是一个社区的努力。要贡献数据集,你只需加入社区,然后你就可以上传数据集。 我们还致力于让人们尽可能容易地创建自己的数据集。作为第一步,我们添加了一个 QAGenerationChain,它为文档提供了问答对,这些问答对可以用来评估文档中的问答任务。
2:缺乏指标
我们有两个解决方案来解决缺乏指标的问题。 第一种解决方案是不使用度量,而是仅仅依靠肉眼观察结果来了解链条/代理的表现。为了帮助解决这个问题,我们已经开发了(并将继续开发)跟踪,一个基于 UI 的链和代理运行的可视化工具。 我们推荐的第二种解决方案是使用语言模型本身来评估输出。为此,我们有一些不同的链条和提示,旨在解决这一问题。
Summarization
一个常见的应用场景是想要对长文档进行摘要。这自然而然地遇到了上下文窗口的限制。与问答不同的是,你不能仅仅通过一些语义搜索技巧选择最相关的文本块(因为在这种情况下,没有特定的问题 - 你想要总结所有内容)。那么你该怎么办呢?
最常见的方法是将文档分成块,然后以递归的方式进行摘要。这意味着你首先单独总结每个块,然后将摘要分组成块,并总结每个摘要块,直到只剩下一个。
Written by xi ming You should follow him on Github